package com.sh.rbac.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sh.rbac.core.common.exception.CustomException;
import com.sh.rbac.core.common.result.ResultCodeEnum;
import com.sh.rbac.core.storage.config.OssClient;
import com.sh.rbac.core.storage.config.StorageFactory;
import com.sh.rbac.core.storage.model.UploadResult;
import com.sh.rbac.domain.dto.file.FileQueryDTO;
import com.sh.rbac.domain.entity.File;
import com.sh.rbac.mapper.FileMapper;
import com.sh.rbac.service.FileService;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import software.amazon.awssdk.core.ResponseInputStream;
import software.amazon.awssdk.services.s3.model.GetObjectResponse;
import software.amazon.awssdk.transfer.s3.model.Download;

import java.io.ByteArrayInputStream;
import java.io.Serializable;

/**
 * @author wb
 * @since 2024-10-01
 */
@Service
public class FileServiceImpl extends ServiceImpl<FileMapper, File>
        implements FileService {

    @Autowired
    private StorageFactory storageFactory;


    @Override
    public String upload(MultipartFile file) {
        try {
            OssClient ossClient = storageFactory.getInstance();

            String originalName = file.getOriginalFilename();
            String contentType = file.getContentType();
            byte[] bytes = file.getBytes();

            String salt = RandomUtil.randomString(16);
            String filename = generateFilename(originalName, salt);

            UploadResult result = ossClient.upload(new ByteArrayInputStream(bytes), bytes.length, filename, contentType);

            File f = new File();
            f.setName(filename);
            f.setType(contentType);
            f.setSalt(salt);
            f.setOriginalName(originalName);
            f.setSize(bytes.length);
            f.setPath(result.getUrl());

            save(f);

            return result.getUrl();
        } catch (Exception e) {
            throw new CustomException(e.getMessage());
        }
    }

    @Override
    public void download(String filename, HttpServletResponse response) {
        try {
            OssClient ossClient = storageFactory.getInstance();
            Download<ResponseInputStream<GetObjectResponse>> streamDownload = ossClient.download(filename);

            try (ResponseInputStream<GetObjectResponse> responseInputStream = streamDownload.completionFuture().join().result()) {
                response.setContentType(responseInputStream.response().contentType());
                response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
                response.setHeader("Content-Disposition", "attachment;filename=" + filename);
                response.getOutputStream().write(responseInputStream.readAllBytes());
            }
        } catch (Exception e) {
            throw new CustomException(ResultCodeEnum.FILE_NOT_FIND);
        }
    }

    @Override
    public boolean removeById(Serializable id) {
        File file = getById(id);
        storageFactory.getInstance().delete(file.getName());
        return super.removeById(id);
    }

    @Override
    public Page<File> getPage(Long current, Long limit, FileQueryDTO fileQueryDTO) {
        String name = fileQueryDTO.getName();

        LambdaQueryWrapper<File> lqw = new LambdaQueryWrapper<>();
        lqw.like(StrUtil.isNotBlank(name), File::getOriginalName, name);

        lqw.orderByDesc(File::getCreateTime);

        return page(Page.of(current, limit), lqw);
    }


    /**
     * 传入文件名返回新的文件名
     *
     * @param fileName 文件名
     * @return 新的文件名
     */
    public static String generateFilename(String fileName, String md5) {
        if (fileName == null) {
            throw new CustomException(ResultCodeEnum.FILE_NOT_FIND);
        }

        // 获取加密的文件名
        String md5FileName = DigestUtil.md5Hex(fileName + md5);

        // 获取文件后缀
        String suffix = fileName.substring(fileName.lastIndexOf("."));

        // 返回新的文件名
        return md5FileName + suffix;
    }
}
